package nfa_generator;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;

/**
 * Node structure for NFAGraph. Keeps track of node name, 
 * token type if an accepting state, 
 * and a mapping of inputs and transitions to other nodes.
 * 
 * @author Joshua
 *
 */
public class NFANode {
	private String name;
	private String token;
	private Map<List<String>, List<NFANode>> transitions;
	
	/**
	 * Empty constructor for NFANode, initializes everything to null and creates an empty transitions map.
	 */
	public NFANode() {
		this.setName(null);
		this.setToken(null);
		transitions = new HashMap<List<String>, List<NFANode>>();
	}

	/**
	 * Getter for node name.
	 * 
	 * @return name - String for name of node.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Setter for node name.
	 * 
	 * @param name - String to set the node name to.
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Getter for token type.
	 * 
	 * @return token - String for the type of token this node accepts.
	 */
	public String getToken() {
		return token;
	}
	
	/**
	 * Checks to see if node is accepting, nodes with what token type they accept are accepting.
	 * If token is null, not accepting.
	 * If token is not null, accepting.
	 * 
	 * @return true if accepting, false if not accepting.
	 */
	public boolean isAccepting() {
		return (token != null);
	}
	
	/**
	 * Setter for the token type.
	 * 
	 * @param token - String to set the type of token this node accepts.
	 */
	public void setToken(String token) {
		this.token = token;
	}
	
	/**
	 * Takes in an input string and a destination node and adds the state transition to the current hashmap of transitions.
	 * 
	 * @param input - List<String> input that the node transitions on.
	 * @param destination - NFANode that is reached on the transition.
	 */
	public void addTransition(List<String> input, NFANode destination) {
		List<NFANode> destinations;
		if(!transitions.containsKey(input)) {
			destinations = new ArrayList<NFANode>();
			destinations.add(destination);
			transitions.put(input, destinations);
		}
		else {
			destinations = transitions.get(input);
			destinations.add(destination);
			transitions.put(input, destinations);
		}
	}
	
	/**
	 * Getter for node transitions based on input.
	 * 
	 * @param input - List<String> on which the node transitions to other nodes.
	 * @return transitions - List<NFANode>, a list of NFANodes reached on the given input from the current node, the value of the given key (input) in the transitions map.
	 */
	public List<NFANode> getTransitions(List<String> input) {
		return transitions.get(input);
	}
	
	/**
	 * Getter for the map of transitions.
	 * 
	 * @return transitions - Map<List<String>, List<NFANode>>, the full map of transitions.
	 */
	public Map<List<String>, List<NFANode>> getTransitionsTable() {
		return transitions;
	}
	
	/**
	 * toString method to better evaluate testing.
	 * 
	 * @return result - String which shows the structure and data it contains for printing.
	 */
	public String toString() {
		String result;
		result = "Node name: " + this.name + "\n";
		result += "Token type: " + this.token + "\n";
		result += "Transitions: \n";
		for(Entry<List<String>, List<NFANode>> entry : transitions.entrySet()) {
			result += "   Input: " + entry.getKey() + "\n";
			for(NFANode node : entry.getValue()) {
				result += "      Node: " + node.getName() + "\n";
			}
		}
		return result;
	}
}